fix: correct Sony ARW2 de-interleave and tone-curve expansion#21
Merged
Conversation
Port of dcraw/LibRaw's sony_curve construction: reduces four u16 control points with `>> 2 & 0xfff`, brackets with 0 and 4095, and fills each segment incrementing by `1 << i`. Returns a 0x4000-entry Vec<u16> for use as `curve[pixel << 1]` during ARW2 block decoding. Includes unit test validating the A7 IV control points against expected dcraw output.
ARW2 (Sony cRAW, e.g. A7 IV/ILCE-7M4) decoded with a vertical comb artifact and ~8x too dark because each 16-pixel block was written to consecutive columns and the 11-bit codes were stored without the Sony tone curve. Port LibRaw's sony_arw2_load_raw: write every other column with alternating even/odd phase and expand through curve[pix << 1] built from the SonyToneCurve tag; set white_level to 0x3ff0.
Malformed blocks where imax == imin cause 15 ordinary pixels to be decoded (instead of 14), pushing `byte_index + 1` to `dp + 17 = raw_width + 1` on the last block of a row. The previous version of `sony_arw2_load_raw` rejected that with a clean error return; the rewrite dropped the check. Restored it. Also appended a comment documenting the tone_curve length invariant (`>= 0x1000` entries; largest index is `0x7ff << 1` = 0xffe).
There was a problem hiding this comment.
Pull request overview
This PR fixes decoding of Sony A7 IV (ILCE-7M4) compressed ARW2 files by correcting block de-interleaving (removing vertical comb striping) and applying Sony’s tone-curve expansion so the decoded pixel domain matches expected brightness/exposure.
Changes:
- Add
build_sony_tone_curve()to construct the ARW2 linearization table from EXIFSonyToneCurve(0x7010). - Rewrite
sony_arw2_load_raw()to de-interleave columns correctly and expand 11-bit codes via the tone curve; update ARW2white_level. - Update Sony loader to read
SonyToneCurvefrom EXIF and pass the derived curve into the ARW2 decoder.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
agno/src/sony_decoder.rs |
Implements ARW2 tone curve building and correct de-interleaving + curve expansion during decode; adds unit tests. |
agno/src/agno_image/load/sony.rs |
Wires EXIF SonyToneCurve extraction into the ARW2 compressed decode path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Sony A7 IV (ILCE-7M4) compressed
.ARWfiles (the ARW2 / lossy cRAW codec) rendered with vertical comb striping and ~8× too dark. The ARW2 decode path had never been exercised by a real file — both committed Sony fixtures (sony.ARW,sony2.ARW) are ILCE-7SM3 uncompressed and take theUncompressed14path — so two bugs shipped:sony_arw2_load_rawwrote each 16-pixel block to consecutive columns. ARW2 actually interleaves: a block fills every other column (stride 2), and consecutive blocks alternate even/odd phase across a 32-column span. This caused the vertical comb artifact. Ported LibRaw/dcraw'scol += 2 … col -= col&1 ? 1 : 31logic.white_level = 0x3fff, leaving the image crushed and dark. They are now expanded through the Sony tone curve (curve[pix << 1]), built from theSonyToneCurveEXIF tag (0x7010), into the ~14-bit linear domain;white_levelis0x3ff0.Changes:
build_sony_tone_curve(port of the dcraw/LibRaw curve construction).sony_arw2_load_raw(de-interleave + curve +white_level 0x3ff0, newtone_curve: &[u16]param); restore the malformed-block row-buffer overread guard.load_sony_rawto read the tone-curve tag from EXIF and pass the built curve.The
Uncompressed14path and all other decoders are untouched.Test plan
cargo test -p agno --no-default-features --features jpeg,png --lib— 217 unit tests pass, including newarw2_deinterleaves_columns_and_applies_tone_curveandbuild_sony_tone_curve_*testssony.ARW,sony2.ARW) still decode correctly — no regressionNote: an integration test against a real ARW2 file is intentionally not committed (the only available samples are personal 35 MB photos); coverage is via synthetic unit tests plus the manual visual verification above.